feat(desktop): open a whole selection, together or one at a time - #33
Merged
Conversation
"Open with" now acts on the selection rather than the one row you happened to
right-click, and the handler is chosen once for all of it. Being asked which
application to use twelve times in a row is not a feature.
Two modes, because a set of files is not one kind of thing:
- **All at once** hands every file to the application in a single invocation,
so an entry taking %F or %U gets them together, which is what "open all of
them" means to the application as well as to the person asking.
- **One at a time** opens a file, waits until the application is finished with
it, and then opens the next. A series of episodes is watched in order and
opening twelve at once is never what anyone meant.
The default is picked from what the files are: video or audio defaults to one
at a time, everything else to all at once, and a single file is not offered a
mode at all. A mixed selection has no shared type, so it gets all at once and
each file opens in its own default application.
**Waiting for an application to finish, without reimplementing Exec.**
`gio launch` returns almost immediately (measured at 17ms): it hands the file
to the desktop's launcher and exits. But the application it starts inherits
our stdio, so the PIPES close when the application does, measured at 3018ms
for a three second app. Waiting on the pipes rather than the process is
therefore a reliable "done with this file" signal, and it costs nothing: the
alternative is parsing the desktop entry's Exec field codes (%f, %F, %u, %U)
ourselves, which is a small parser and a large number of ways to hand an
application the wrong thing.
**The case that breaks it, handled rather than ignored.** A single-instance
application hands the file to the copy already running and exits at once, so
there is no "it closed" to wait for. A close under one second is read as that
rather than as somebody watching an episode in under a second: the run parks
and offers Open next instead of advancing. Auto-advancing there would dump the
whole list into the running player, which is the exact thing this mode exists
to prevent. The dialog says so in as many words rather than looking stalled.
Both fixture bugs found while testing this are worth knowing, and are recorded
in the test that hit them:
- `Exec=sleep 1` does not work as a fake player, because gio appends the file
to the Exec line and `sleep 1 /tmp/a.mkv` dies instantly with "invalid time
interval". The code then correctly reads that as a hand-off, so the naive
fixture tests the opposite of what it appears to.
- A one second app is *under* the hand-off threshold. The fixture has to be
clearly above it or the test asserts the wrong branch. That also moved the
threshold from 1500ms to 1000ms, which sits well clear of a real hand-off
(tens of ms) and nowhere near somebody actually using a file.
Verified in headless Chromium under the app's real CSP: selecting three .mkv
files names the count in the menu ("Open 3 files with…"), the dialog defaults
to one at a time because they are video, the run carries all three paths and a
null handler, the hand-off parks with "1 of 3" and an explanation, Open next
advances exactly once, and a lone markdown file is offered no mode at all.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VScug5VRbcTuhiAoieeQ52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
"Open with" now acts on the selection rather than the one row you happened to
right-click, and the handler is chosen once for all of it. Being asked which
application to use twelve times in a row is not a feature.
Two modes, because a set of files is not one kind of thing:
so an entry taking %F or %U gets them together, which is what "open all of
them" means to the application as well as to the person asking.
it, and then opens the next. A series of episodes is watched in order and
opening twelve at once is never what anyone meant.
The default is picked from what the files are: video or audio defaults to one
at a time, everything else to all at once, and a single file is not offered a
mode at all. A mixed selection has no shared type, so it gets all at once and
each file opens in its own default application.
Waiting for an application to finish, without reimplementing Exec.
gio launchreturns almost immediately (measured at 17ms): it hands the fileto the desktop's launcher and exits. But the application it starts inherits
our stdio, so the PIPES close when the application does, measured at 3018ms
for a three second app. Waiting on the pipes rather than the process is
therefore a reliable "done with this file" signal, and it costs nothing: the
alternative is parsing the desktop entry's Exec field codes (%f, %F, %u, %U)
ourselves, which is a small parser and a large number of ways to hand an
application the wrong thing.
The case that breaks it, handled rather than ignored. A single-instance
application hands the file to the copy already running and exits at once, so
there is no "it closed" to wait for. A close under one second is read as that
rather than as somebody watching an episode in under a second: the run parks
and offers Open next instead of advancing. Auto-advancing there would dump the
whole list into the running player, which is the exact thing this mode exists
to prevent. The dialog says so in as many words rather than looking stalled.
Both fixture bugs found while testing this are worth knowing, and are recorded
in the test that hit them:
Exec=sleep 1does not work as a fake player, because gio appends the fileto the Exec line and
sleep 1 /tmp/a.mkvdies instantly with "invalid timeinterval". The code then correctly reads that as a hand-off, so the naive
fixture tests the opposite of what it appears to.
clearly above it or the test asserts the wrong branch. That also moved the
threshold from 1500ms to 1000ms, which sits well clear of a real hand-off
(tens of ms) and nowhere near somebody actually using a file.
Verified in headless Chromium under the app's real CSP: selecting three .mkv
files names the count in the menu ("Open 3 files with…"), the dialog defaults
to one at a time because they are video, the run carries all three paths and a
null handler, the hand-off parks with "1 of 3" and an explanation, Open next
advances exactly once, and a lone markdown file is offered no mode at all.
pnpm test556 passing,pnpm -r typecheckclean,pnpm smoke:desktopall three guards ok.🤖 Generated with Claude Code
https://claude.ai/code/session_01VScug5VRbcTuhiAoieeQ52